#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace AbstractClass
{
    /// <summary>
    /// Represents a Complex number.
    /// </summary>
    [DebuggerDisplay("{Real} + {Imaginary}i")]
    public struct ComplexNumber
    {
        /// <summary>
        /// Initializes a new instance of the <see cref = "ComplexNumber" />.
        /// </summary>
        /// <param name="real">The real part.</param>
        /// <param name="imaginary">The imaginary part.</param>
        public ComplexNumber(double real, double imaginary) : this()
        {
            Real = real;
            Imaginary = imaginary;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref = "ComplexNumber" />.
        /// </summary>
        /// <param name="complexNumber">Another complex number.</param>
        public ComplexNumber(ComplexNumber complexNumber) : this()
        {
            Real = complexNumber.Real;
            Imaginary = complexNumber.Imaginary;
        }

        /// <summary>
        ///   Initializes a new instance of the <see cref = "ComplexNumber" />.
        /// </summary>
        /// <param name="real">The real part.</param>
        public ComplexNumber(double real) : this()
        {
            Real = real;
            Imaginary = 0;
        }

        /// <summary>
        ///   Initializes a new instance of the <see cref = "ComplexNumber" />.
        /// </summary>
        /// <param name = "complexNumber">The complex number as a string.</param>
        public ComplexNumber(string complexNumber) : this()
        {
            ComplexNumber temp;
            if (TryParse(complexNumber, out temp))
            {
                Real = temp.Real;
                Imaginary = temp.Imaginary;
            }
            else
            {
                Real = 0;
                Imaginary = 0;
            }
        }


        /// <summary>
        ///   Gets or sets the real part of this instance.
        /// </summary>
        /// <value>The real part.</value>
        public double Real { get; set; }

        /// <summary>
        ///   Gets or sets the imaginary part of this instance.
        /// </summary>
        /// <value>The imaginary part.</value>
        public double Imaginary { get; set; }

        /// <summary>
        /// 0 + 0i
        /// </summary>
        /// <value>0 + 0i.</value>
        public static ComplexNumber Zero
        {
            get { return new ComplexNumber(0, 0); }
        }

        /// <summary>
        /// 0 + i
        /// </summary>
        /// <value>0 + i</value>
        public static ComplexNumber I
        {
            get { return new ComplexNumber(0, 1); }
        }

        /// <summary>
        /// 1 + 0i
        /// </summary>
        /// <value>1 + 0i</value>
        public static ComplexNumber One
        {
            get { return new ComplexNumber(1, 0); }
        }

        /// <summary>
        /// Gets the modulus of the complex number.
        /// </summary>
        /// <value>The modulus of the complex number.</value>
        public double Modulus
        {
            get { return Math.Sqrt(Real * Real + Imaginary * Imaginary); }
        }

        /// <summary>
        /// Gets the argument of the complex number.
        /// </summary>
        /// <value>The argument of the complex number.</value>
        public double Argument
        {
            get { return Math.Atan(Imaginary / Real); }
        }

        /// <summary>
        /// Gets the squared magnitude (Modulus ^ 2) of the complex number.
        /// </summary>
        /// <value>The squared magnitude of the complex number.</value>
        public double SquaredMagnitude
        {
            get { return (Real * Real + Imaginary * Imaginary); }
        }

        /// <summary>
        /// Gets the conjugate of the complex number.
        /// </summary>
        /// <value>The conjugate of the complex number.</value>
        public ComplexNumber Conjugate
        {
            get { return new ComplexNumber(Real, -Imaginary); }
        }

        /// <summary>
        /// Gets a value indicating whether the Complex number is pure real number.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is pure real number; otherwise, <c>false</c>.
        /// </value>
        public bool IsPureReal
        {
            get { return Imaginary == 0; }
        }

        /// <summary>
        /// Gets a value indicating whether the Complex number is pure imaginary number.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is pure imaginary number; otherwise, <c>false</c>.
        /// </value>
        public bool IsPureImaginary
        {
            get { return Real == 0; }
        }

        /// <summary>
        /// Gets the polar representation of the complex number.
        /// </summary>
        /// <param name = "modulus">The modulus of the complex number.</param>
        /// <param name = "argument">The argument of the complex number.</param>
        /// <returns>A <see cref="ComplexNumber"/>.</returns>
        public static ComplexNumber Polar(double modulus, double argument)
        {
            return new ComplexNumber(
                modulus * Math.Cos(argument),
                modulus * Math.Sin(argument));
        }


        /// <summary>
        ///   Returns the string representation of the Complex number in a+bi format.
        /// </summary>
        /// <returns>
        ///   A <see cref = "T:System.String"></see> containing a+bi representation of the Complex number.
        /// </returns>
        public override string ToString()
        {
            return String.Format("{0}{1}{2}i", Real, ((Imaginary < 0) ? '-' : '+'), Math.Abs(Imaginary));
        }


        /// <summary>
        /// Adds two complex numbers.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">Another complex number.</param>
        /// <returns>The result of the addition.</returns>
        public static ComplexNumber operator +(ComplexNumber a, ComplexNumber b)
        {
            return new ComplexNumber(a.Real + b.Real, a.Imaginary + b.Imaginary);
        }

        /// <summary>
        /// Adds a complex number with a real number.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">A real number.</param>
        /// <returns>The result of the addition.</returns>
        public static ComplexNumber operator +(ComplexNumber a, double b)
        {
            return new ComplexNumber(a.Real + b, a.Imaginary);
        }

        /// <summary>
        /// Adds a real number to a complex number.
        /// </summary>
        /// <param name="a">A real number.</param>
        /// <param name="b">A complex number.</param>
        /// <returns>The result of the addition.</returns>
        public static ComplexNumber operator +(double a, ComplexNumber b)
        {
            return new ComplexNumber(a + b.Real, b.Imaginary);
        }


        /// <summary>
        /// Subtracts two complex numbers.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">Another complex number.</param>
        /// <returns>The result of the subtraction.</returns>
        public static ComplexNumber operator -(ComplexNumber a, ComplexNumber b)
        {
            return new ComplexNumber(a.Real - b.Real, a.Imaginary - b.Imaginary);
        }

        /// <summary>
        /// Subtracts a real number from a complex number.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">A real number.</param>
        /// <returns>The result of the subtraction.</returns>
        public static ComplexNumber operator -(ComplexNumber a, double b)
        {
            return new ComplexNumber(a.Real - b, a.Imaginary);
        }

        /// <summary>
        /// Subtracts a complex number from a real number.
        /// </summary>
        /// <param name="a">A real number.</param>
        /// <param name="b">A complex number.</param>
        /// <returns>The result of the subtraction.</returns>
        public static ComplexNumber operator -(double a, ComplexNumber b)
        {
            return new ComplexNumber(a - b.Real, b.Imaginary);
        }

        /// <summary>
        /// Negates a complex number.
        /// </summary>
        /// <param name="a">A complex number to negate.</param>
        /// <returns>The result of the negation.</returns>
        public static ComplexNumber operator -(ComplexNumber a)
        {
            return new ComplexNumber(-a.Real, -a.Imaginary);
        }

        /// <summary>
        /// Multiplies two complex numbers.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">Another complex number.</param>
        /// <returns>The result of the multiplication.</returns>
        public static ComplexNumber operator *(ComplexNumber a, ComplexNumber b)
        {
            return new ComplexNumber(
                a.Real * b.Real - a.Imaginary * b.Imaginary,
                a.Real * b.Imaginary + a.Imaginary * b.Real);
        }

        /// <summary>
        /// Multiplies a complex number with a real number.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">A real number.</param>
        /// <returns>The result of the multiplication.</returns>
        public static ComplexNumber operator *(ComplexNumber a, double b)
        {
            return new ComplexNumber(b) * a;
        }

        /// <summary>
        /// Multiplies a real number with a complex number.
        /// </summary>
        /// <param name="a">A real number.</param>
        /// <param name="b">A complex number.</param>
        /// <returns>The result of the multiplication.</returns>
        public static ComplexNumber operator *(double a, ComplexNumber b)
        {
            return new ComplexNumber(b) * a;
        }


        /// <summary>
        /// Divides two complex numbers.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">Another complex number.</param>
        /// <returns>The result of the division.</returns>
        /// <exception cref="DivideByZeroException"><paramref name="b"/> is equal to <see cref="Zero"/>.</exception>
        public static ComplexNumber operator /(ComplexNumber a, ComplexNumber b)
        {
            double divider = b.Real * b.Real + b.Imaginary * b.Imaginary;

            if (divider == 0)
                throw new DivideByZeroException();

            return new ComplexNumber(
                (a.Real * b.Real + a.Imaginary * b.Imaginary) / divider,
                (a.Imaginary * b.Real - a.Real * b.Imaginary) / divider);
        }

        /// <summary>
        /// Divides a complex number by a real number.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">A real number.</param>
        /// <returns>The result of the division.</returns>
        public static ComplexNumber operator /(ComplexNumber a, double b)
        {
            return a * (1 / b);
        }

        /// <summary>
        /// Divides a real number by a complex number.
        /// </summary>
        /// <param name="a">A real number.</param>
        /// <param name="b">A complex number.</param>
        /// <returns>The result of the division.</returns>
        public static ComplexNumber operator /(double a, ComplexNumber b)
        {
            return a * b.Conjugate * (1 / b.Modulus * b.Modulus);
        }

        /// <summary>
        /// Determines whether two complex numbers are equal.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">Another complex number.</param>
        /// <returns><c>true</c> if two complex numbers are equal; otherwise, <c>false</c>.</returns>
        public static bool operator ==(ComplexNumber a, ComplexNumber b)
        {
            return (a.Real == b.Real && a.Imaginary == b.Imaginary);
        }

        /// <summary>
        /// Determines whether a complex number value is equal to a real number.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">A real number.</param>
        /// <returns><c>true</c> if the complex numbers is equal to the real number; otherwise, <c>false</c>.</returns>
        public static bool operator ==(ComplexNumber a, double b)
        {
            return a == new ComplexNumber(b);
        }

        /// <summary>
        /// Determines whether a real number value is equal to a complex number.
        /// </summary>
        /// <param name="a">A real number.</param>
        /// <param name="b">A complex number.</param>
        /// <returns><c>true</c> if the complex numbers is equal to the real number; otherwise, <c>false</c>.</returns>
        public static bool operator ==(double a, ComplexNumber b)
        {
            return new ComplexNumber(a) == b;
        }

        /// <summary>
        /// Determines whether two complex numbers are not equal.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">Another complex number.</param>
        /// <returns><c>true</c> if two complex numbers are not equal; otherwise, <c>false</c>.</returns>
        public static bool operator !=(ComplexNumber a, ComplexNumber b)
        {
            return (a.Real != b.Real || a.Imaginary != b.Imaginary);
        }

        /// <summary>
        /// Determines whether two complex numbers are not equal.
        /// </summary>
        /// <param name="a">A complex number.</param>
        /// <param name="b">A real number.</param>
        /// <returns><c>true</c> if the complex numbers is not equal to the real number; otherwise, <c>false</c>.</returns>
        public static bool operator !=(ComplexNumber a, double b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Determines whether a real number value is not equal to a complex number.
        /// </summary>
        /// <param name="a">A real number.</param>
        /// <param name="b">A complex number.</param>
        /// <returns><c>true</c> if the complex numbers is not equal to the real number; otherwise, <c>false</c>.</returns>
        public static bool operator !=(double a, ComplexNumber b)
        {
            return !(a == b);
        }


        /// <summary>
        /// Determines whether a specified complex number is equal to the current instance.
        /// </summary>
        /// <param name="other">The other complex number.</param>
        /// <returns><c>true</c> if two complex numbers are equal; otherwise, <c>false</c>.</returns>
        public bool Equals(ComplexNumber other)
        {
            return (Real == other.Real && Imaginary == other.Imaginary);
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        /// 	<c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj.GetType() == typeof (ComplexNumber) && Equals((ComplexNumber) obj);
        }

        /// <summary>
        ///   Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        ///   A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            unchecked
            {
                return Real.GetHashCode() ^ Imaginary.GetHashCode();
            }
        }

        /// <summary>
        /// Parses the specified <paramref name="complexString"/> as a <see cref="ComplexNumber"/>.
        /// </summary>
        /// <param name="complexString">The complex number string.</param>
        /// <returns>A complex number specified by a string.</returns>
        /// <exception cref="FormatException">Specified string is not in proper complex number format (a+bi).</exception>
        public static ComplexNumber Parse(string complexString)
        {
            const string realPattern = "^[+-]?(?:\\d+\\.?\\d*|\\d*\\.?\\d+)[\\r\\n]*$";
            const string imaginaryPattern = "^[+-]?(?:\\d+\\.?\\d*|\\d*\\.?\\d+)[\\r\\n]*[i]$";
            const string complexPattern =
                "^(?<RePart>([+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)))(?<ImPart>([+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)))[i]$";

            var regex = new Regex(realPattern);
            if (regex.IsMatch(complexString))
            {
                Match match = regex.Match(complexString);
                double real = double.Parse(match.Value);
                return new ComplexNumber(real);
            }
            regex = new Regex(imaginaryPattern);
            if (regex.IsMatch(complexString))
            {
                Match match = regex.Match(complexString);
                double imaginary = double.Parse(match.Value.Replace("i", ""));
                return new ComplexNumber(0d, imaginary);
            }
            regex = new Regex(complexPattern);
            if (regex.IsMatch(complexString))
            {
                Match match = regex.Match(complexString);
                double realPart = double.Parse(match.Groups["RePart"].Value);
                double imaginaryPart = double.Parse(match.Groups["ImPart"].Value);
                return new ComplexNumber(realPart, imaginaryPart);
            }

            throw new FormatException(LanguageResource.NotInAcceptableComplexNumberFormat);
        }

        /// <summary>
        /// Tries to parse the specified <paramref name="complexString"/> as a <see cref="ComplexNumber"/>. If parsing is successful
        /// <paramref name="complexNumber"/> will contained the parsed <see cref="ComplexNumber"/> else it will contain a default value
        /// 0+0i.
        /// </summary>
        /// <param name="complexString">The complex string.</param>
        /// <param name="complexNumber">The complex number.</param>
        /// <returns><c>true</c> if parsing successful; otherwise, <c>false</c>.</returns>
        public static bool TryParse(string complexString, out ComplexNumber complexNumber)
        {
            try
            {
                complexNumber = Parse(complexString);
                return true;
            }
            catch
            {
                complexNumber = default(ComplexNumber);
                return false;
            }
        }

        /// <summary>
        /// Returns a complex number equals to this instance raised to the power of <paramref name="exponent"/>.
        /// </summary>
        /// <param name="exponent">The exponent.</param>
        /// <returns>A complex number equals to this instance raised to the power of <paramref name="exponent"/>.</returns>
        public ComplexNumber ToThePower(ComplexNumber exponent)
        {
            return QMath.Exp(exponent * QMath.Log(this));
        }

        /// <summary>
        /// Returns a complex number equals to this instance raised to the power of <paramref name="exponent"/>.
        /// </summary>
        /// <param name="exponent">The exponent.</param>
        /// <returns>A complex number equals to this instance raised to the power of <paramref name="exponent"/>.</returns>
        public ComplexNumber ToThePower(double exponent)
        {
            return QMath.Exp(exponent * QMath.Log(this));
        }
    }
}